import math
import numpy as np
import pandas as pd
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication, QFileDialog, QMessageBox
from openpyxl import load_workbook
from scipy.signal import find_peaks
import bisect
from datetime import datetime, timedelta

from astropy.timeseries import LombScargle
from pyhht.emd import EMD
import pywt
from pywt import dwt
from pyemd import emd
from scipy.signal import find_peaks, lombscargle
import matplotlib.pyplot as plt
from scipy.stats import pearsonr
from sklearn.metrics import mean_absolute_error, mean_squared_error


class InputDialog(QtWidgets.QDialog):
    def __init__(self, txt, parent=None):
        super().__init__(parent)
        self.setWindowTitle(txt)
        self.setup_ui()

    def setup_ui(self):
        # 主垂直布局
        layout = QtWidgets.QVBoxLayout(self)

        # 创建三个水平布局的输入行
        self.create_input_row(layout, "分解层数:", "param1")
        self.create_input_row(layout, "重构起始层数:", "param2")
        self.create_input_row(layout, "重构结束层数:", "param3")

        # 添加确定/取消按钮
        button_box = QtWidgets.QDialogButtonBox(
            QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel,
            QtCore.Qt.Horizontal, self
        )
        button_box.accepted.connect(self.accept)
        button_box.rejected.connect(self.reject)
        layout.addWidget(button_box)

    def create_input_row(self, parent_layout, label_text, placeholder):
        # 创建水平布局
        h_layout = QtWidgets.QHBoxLayout()

        # 添加标签
        label = QtWidgets.QLabel(label_text)
        h_layout.addWidget(label)

        # 添加输入框
        line_edit = QtWidgets.QLineEdit()
        line_edit.setPlaceholderText(placeholder)
        h_layout.addWidget(line_edit)

        # 将行添加到父布局
        parent_layout.addLayout(h_layout)

        # 保存输入框引用
        setattr(self, f"line_edit_{placeholder}", line_edit)

    def get_inputs(self):
        return (
            self.line_edit_param1.text(),
            self.line_edit_param2.text(),
            self.line_edit_param3.text()
        )


def get_file_name():
    file_path, _ = QFileDialog.getOpenFileName(
        None,  # 父窗口
        "选择文件",  # 标题
        "",  # 起始目录（空字符串表示当前目录）
        "所有文件 (*);;文本文件 (*.txt);;Python文件 (*.py)"
    )
    return file_path


def get_directory():
    directory = QFileDialog.getExistingDirectory(
        None,
        "选择目录",
        "",  # 起始目录
        QFileDialog.ShowDirsOnly  # 只显示目录
    )
    return directory


def read_excel_range(file_path, cell_range, sheet_name='水位'):
    """
    读取Excel文件中指定范围的单元格数据
    :param file_path: Excel文件路径
    :param sheet_name: 工作表名称
    :param cell_range: 单元格范围，如'A3:B55'
    :return: 二维列表形式的数据
    """
    wb = load_workbook(filename=file_path, read_only=True, data_only=True)
    sheet = wb[sheet_name]
    data = []

    for row in sheet[cell_range]:
        row_data = []
        for cell in row:
            row_data.append(cell.value)
        data.append(row_data)

    wb.close()
    return data


def get_satellite_label(name, label):
    if name[0] == '1' and label[0] == 'L':
        if name[1:3] == '01' and label[1] == '1':
            return True
        elif name[1:3] == '02' and label[1] == '2':
            return True
        elif name[1:3] == '03' and label[1] == '5':
            return True
        else:
            return False
    elif name[0] == '2' and label[0] == 'R':
        if name[1:3] == '04' and label[1] == '1':
            return True
        elif name[1:3] == '05' and label[1] == '2':
            return True
        else:
            return False
    elif name[0] == '3' and label[0] == 'B':
        if name[1:3] == '06' and label[1] == '1':
            return True
        elif name[1:3] == '07' and label[1] == '6':
            return True
        elif name[1:3] == '08' and label[1] == '7':
            return True
        else:
            return False
    elif name[0] == '4' and label[0] == 'E':
        if name[1:3] == '09' and label[1] == '1':
            return True
        elif name[1:3] == '10' and label[1] == '5':
            return True
        elif name[1:3] == '11' and label[1] == '7':
            return True
        elif name[1:3] == '12' and label[1] == '8':
            return True
        else:
            return False
    else:
        return False


def read_satellite_data(satellite_path):
    data = []
    with open(satellite_path, 'r') as f:
        for line in f:
            if line.startswith('%') or not line.strip():  # 跳过注释和空行
                continue
            parts = line.split()
            try:
                time = f"{parts[0]} {parts[1]}"
                sat = parts[2]
                az = float(parts[3])
                el = float(parts[4])
                snr = float(parts[5])
                mp = float(parts[6])
                data.append([time, sat, az, el, snr, mp])
            except (IndexError, ValueError) as e:
                print(f"解析失败: {line} | 错误: {e}")
    return pd.DataFrame(data, columns=['TIME', 'SAT', 'AZ', 'EL', 'SNR', 'MP'])


def get_edit_figure(window, label):
    try:
        if label == 'azl':
            txt = window.lineEdit_7.text()
            window.lineEdit_7.clearFocus()
            window.az_range[0] = float(txt)
        elif label == 'azh':
            txt = window.lineEdit_8.text()
            window.lineEdit_8.clearFocus()
            window.az_range[1] = float(txt)
        elif label == 'ell':
            txt = window.lineEdit_9.text()
            window.lineEdit_9.clearFocus()
            window.el_range[0] = float(txt)
        elif label == 'elh':
            txt = window.lineEdit_10.text()
            window.lineEdit_10.clearFocus()
            window.el_range[1] = float(txt)
        elif label == 'ath':
            txt = window.lineEdit_11.text()
            window.lineEdit_11.clearFocus()
            window.ant_high = float(txt)
        elif label == 'mns':
            txt = window.lineEdit_17.text()
            window.lineEdit_17.clearFocus()
            window.min_snr = float(txt)
        elif label == 'pks':
            txt = window.lineEdit_19.text()
            window.lineEdit_19.clearFocus()
            window.peak_snr = float(txt)
        elif label == 'amp':
            txt = window.lineEdit_20.text()
            window.lineEdit_20.clearFocus()
            window.amplitude = float(txt)
        elif label == 'vhl':
            txt = window.lineEdit_13.text()
            window.lineEdit_13.clearFocus()
            window.valid_high[0] = float(txt)
        elif label == 'vhh':
            txt = window.lineEdit_14.text()
            window.lineEdit_14.clearFocus()
            window.valid_high[1] = float(txt)
    except:
        QMessageBox.warning(window, "错误", "请输入正确的数字")


def preprocess_satellite_data(df, ele_s=5, ele_d=15, ca=1):
    valid_indices = []

    for sat, group in df.groupby('SAT'):
        # ===== 1. 数据准备 =====
        df_sat = group.sort_values('TIME').reset_index(drop=True)
        orig_idx = group.index.tolist()

        # ===== 2. 时间戳处理 =====
        tim_str = df_sat['TIME'].str.replace(r'\D', '', regex=True).str[:14]
        tim_all = pd.to_datetime(tim_str, format='%Y%m%d%H%M%S', exact=True)

        # ===== 3. 分割点检测 =====
        # 时间跳变检测
        time_diff = np.diff(tim_all.view('int64') // 10 ** 9)
        time_jumps = np.where(time_diff > time_diff[0] * 10)[0] + 1 if len(time_diff) > 0 else []

        # 高度角跳变检测
        ele = df_sat['EL'].values
        ele_diff = np.diff(ele)
        ele_jumps = np.where(np.abs(ele_diff) > 1)[0] + 1

        # 峰值检测（参数与MATLAB一致）
        peaks, _ = find_peaks(ele, prominence=1, height=np.median(ele))

        # ===== 4. 动态调整分段索引 =====
        split_points = np.unique(np.concatenate([time_jumps, ele_jumps, peaks]))
        split_points.sort()
        jd_all = [0] + split_points.tolist() + [len(ele) - 1]

        for i in range(1, len(jd_all) - 1):
            jd_all[i] += 1

        for n in range(len(jd_all) - 1):
            start, end = jd_all[n], jd_all[n + 1]
            segment = df_sat.iloc[start:end + 1]

            if segment['EL'].min() < ele_s and segment['EL'].max() > ele_d:
                mask = (segment['EL'] > (ele_s - ca)) & (segment['EL'] < (ele_s + ca))
                candidates = segment[mask]

                if not candidates.empty:
                    delta = (candidates['EL'] - ele_s).abs()
                    closest_idx = delta.idxmin()
                    valid_indices.append(orig_idx[closest_idx])

    result_df = df.loc[list(set(valid_indices))].sort_index()
    return result_df


def fresnel_zone(freq, elev_deg, h_ant, azim_deg):
    """
    计算菲涅尔区椭圆参数
    :param freq: 频率编号 (1:L1, 2:L2, 5:L5)
    :param elev_deg: 卫星高度角（度）
    :param h_ant: 天线高度（米）
    :return: (A, B, R) 长半轴、短半轴、中心距（米）
    """
    # 物理常量
    LIGHT_SPEED = 299792458  # 光速 m/s
    FREQ_MAP = {1: 1575.42e6, 2: 1227.6e6, 5: 1176.45e6}

    if freq not in FREQ_MAP:
        raise ValueError(f"无效频率 {freq}，仅支持 1(L1)/2(L2)/5(L5)")

    # 计算波长参数
    wavelength = LIGHT_SPEED / FREQ_MAP[freq]
    delta = wavelength / 2  # 半波长延迟

    # 三角函数计算
    e_rad = math.radians(elev_deg)
    sin_e = math.sin(e_rad)
    tan_e = math.tan(e_rad)

    # 椭圆参数（MATLAB公式）
    B = math.sqrt((2 * delta * h_ant / sin_e) + (delta / sin_e) ** 2)
    A = B / sin_e
    R = (h_ant + delta / sin_e) / tan_e

    return A, B, R


def convert_time(time_str):
    """将 '2020/12/01 07:08:30.0' 转换为 20201201070830 的整数"""
    date_part, time_part = time_str.split()

    # 处理日期部分 (替换斜杠)
    clean_date = date_part.replace('/', '')

    # 处理时间部分 (去掉冒号和毫秒)
    clean_time = time_part.split('.')[0].replace(':', '')

    return int(clean_date + clean_time)


def matlab_sortrows(arr, col):
    """严格模拟MATLAB的sortrows行为"""
    # 生成稳定排序索引 (使用mergesort算法)
    sorted_indices = np.argsort(arr[:, col - 1], kind='mergesort')  # 注意col-1

    # 应用排序
    return arr[sorted_indices]


def matlab_style_findpeaks(ele_all):
    """
    严格模拟MATLAB的findpeaks在重复最大值场景下的行为
    返回格式：(peak_poi, peak_loc)
    其中peak_loc为1-based索引（与MATLAB一致）
    """
    # 第一步：定位所有候选峰值
    locs, props = find_peaks(
        ele_all,
        prominence=0,  # 禁用突出度过滤
        width=0  # 禁用宽度过滤
    )

    # 第二步：后处理修正平坦区域
    peak_poi = []
    peak_loc = []

    for idx in locs:
        # 当前候选峰值
        current_val = ele_all[idx]

        # 向前搜索起始点
        start = idx
        while start > 0 and ele_all[start - 1] == current_val:
            start -= 1

        # 记录第一个出现位置
        peak_poi.append(current_val)
        peak_loc.append(start + 1)  # 转为1-based索引

    # 去重处理
    unique_dict = {}
    for loc, val in zip(peak_loc, peak_poi):
        if loc not in unique_dict or unique_dict[loc] < val:
            unique_dict[loc] = val

    # 排序并转换为数组
    sorted_locs = sorted(unique_dict.keys())
    sorted_poi = [unique_dict[loc] for loc in sorted_locs]

    return np.array(sorted_poi), np.array(sorted_locs)


def _init(x, t, fig, hifac, ofac, a_usr):
    """参数初始化函数"""
    # 输入校验
    x = np.asarray(x).flatten()
    t = np.asarray(t).flatten()
    if len(x) != len(t):
        raise ValueError("x和t长度必须相同")

    # 去除重复时间点
    t_unique, idx = np.unique(t, return_index=True)
    if len(t_unique) != len(t):
        # print("警告：检测到重复时间点，已自动去重")
        t = t_unique
        x = x[idx]

    # 计算基本参数
    T = t[-1] - t[0]
    nt = len(t)
    nf = int(round(0.5 * ofac * hifac * nt))
    f = np.arange(1, nf + 1) / (T * ofac)  # 严格对应Matlab的f生成逻辑

    # 处理显著性水平
    a = [0.001, 0.005, 0.01, 0.05, 0.1, 0.5] if a_usr is None else []
    a_usr = sorted(a_usr) if a_usr is not None else []

    return x, t, hifac, ofac, a, -f


def lomb(x, t, fig=0, hifac=1, ofac=4, a_usr=None):
    """
    Python版Lomb-Scargle周期图计算，严格遵循Matlab原版实现逻辑

    参数：
    x : 输入信号向量
    t : 时间坐标向量
    fig : 是否绘图 (0/1)
    hifac : 最高频率倍数
    ofac : 过采样因子
    a_usr : 自定义显著性水平列表

    返回：
    P : 归一化周期图
    f : 频率数组
    alpha : 统计显著性水平
    """
    # 参数校验与初始化
    x, t, hifac, ofac, a, f = _init(x, t, fig, hifac, ofac, a_usr)
    nt = len(t)
    nf = len(f)

    # 数据标准化
    mx = np.mean(x)
    x = x - mx
    vx = np.var(x)
    if vx == 0:
        raise ValueError("输入信号x的方差为零")

    # 主计算循环
    P = np.zeros(nf)
    for i in range(nf):
        wt = 2 * np.pi * f[i] * t
        swt = np.sin(wt)
        cwt = np.cos(wt)

        # 计算ωτ
        Ss2wt = 2 * np.dot(cwt, swt)  # Σsin(2ωt)
        Sc2wt = np.dot(cwt - swt, cwt + swt)  # Σcos(2ωt)
        wtau = 0.5 * np.arctan2(Ss2wt, Sc2wt)

        swtau = np.sin(wtau)
        cwtau = np.cos(wtau)

        # 计算正交分量
        swttau = swt * cwtau - cwt * swtau  # sin(ω(t-τ))
        cwttau = cwt * cwtau + swt * swtau  # cos(ω(t-τ))

        # 计算功率
        term1 = np.dot(x, cwttau) ** 2 / np.dot(cwttau, cwttau)
        term2 = np.dot(x, swttau) ** 2 / np.dot(swttau, swttau)
        P[i] = (term1 + term2) / (2 * vx)

    # 统计显著性计算
    M = 2 * nf / ofac
    alpha = 1 - (1 - np.exp(-P)) ** M
    # 小概率近似处理
    mask = alpha < 0.1
    alpha[mask] = M * np.exp(-P[mask])

    return P, f, alpha


def gnss_height_inversion(df, params):
    """
    MATLAB严格等效版海平面高度反演
    参数:
        df - 输入DataFrame (来自read_satellite_data)
        params - 参数字典，包含以下键：
            ele_s/ele_d: 仰角范围(度)
            azi_s/azi_d: 方位角范围(度)
            Ant_h: 天线高度(米)
            data_num: 最小有效数据点数
            L_r: 波长参数(米)
            zqb_s: 信噪比阈值
            peak_s: 峰值功率阈值
            h_s/h_d: 有效高度范围(米)
            method: 信号分离方法 (1:多项式, 2:EMD, 3:小波)
    返回:
        results - 包含所有结果的字典，键与MATLAB的fpfile11.mat一致
    """
    # 参数解包
    ele_s = params['ele_s']
    ele_d = params['ele_d']
    azi_s = params['azi_s']
    azi_d = params['azi_d']
    Ant_h = params['Ant_h']
    data_num = params['data_num']
    L_r = params['L_r']
    zqb_s = params['zqb_s']
    peak_s = params['peak_s']
    h_s = params['h_s']
    h_d = params['h_d']
    method = params['method']
    p1 = params['p1']
    p2 = params['p2']
    p3 = params['p3']

    # 转换为MATLAB矩阵格式 (列顺序: 时间,卫星号,仰角,SNR,方位角)

    df['TIME'] = df['TIME'].apply(convert_time)
    df['SAT'] = df['SAT'].str[1:]
    aaaa4 = df[['TIME', 'SAT', 'EL', 'SNR', 'AZ']].values
    aaaa4[:, 1] = aaaa4[:, 1].astype(int)  # 卫星号为整数

    # 主处理流程 (严格MATLAB等效)
    aaaa5 = matlab_sortrows(aaaa4, 2)  # sortrows等效
    wx_num = np.unique(aaaa5[:, 1])

    results = {
        'bbb1': [],
        'frp1': [], 'frp2': [], 'frp3': [],
        'frp5': [], 'frp6': [],
        'mpeak': [], 'rightf': []
    }
    i = 0

    for u in wx_num:
        m = np.where(aaaa5[:, 1] == u)[0]
        if not m.size:
            continue

        w1, w2 = m[0], m[-1]
        cccc = aaaa5[w1:w2 + 1, :]

        # 数据列提取
        tim_all = cccc[:, 0].astype(np.double)
        ele_all = cccc[:, 2]
        azi_all = cccc[:, 4]
        snr_all = cccc[:, 3]

        # 方位角修正
        azi_all[azi_all > 180] -= 360

        # 时间分段检测
        datim = [datetime.strptime(str(int(t)), '%Y%m%d%H%M%S') for t in tim_all]
        catim = np.diff([t.timestamp() for t in datim])
        tim_point = np.where(catim > 10 * catim[0])[0] + 1 if catim.size else []

        # 仰角分段检测
        caele = np.diff(ele_all)
        ele_point = np.where(np.abs(caele) > 1)[0] + 1

        # 峰值检测
        peak_poi, peak_loc = matlab_style_findpeaks(ele_all)
        d_all = np.unique(np.concatenate([tim_point, ele_point, peak_loc]))

        # 分段索引
        jd_all = np.concatenate([[0], d_all, [len(tim_all)]])
        d_num = len(jd_all) - 1

        for n in range(d_num):
            # 获取当前分段范围 (MATLAB索引转Python索引)
            start = jd_all[n] - 1  # MATLAB 1-based → Python 0-based
            end = jd_all[n + 1] - 1

            # 动态调整索引 (MATLAB等效逻辑)
            if jd_all[n + 1] != jd_all[-1]:
                jd_all[n + 1] += 1  # 修改后续索引

            # 数据切片 (包含end索引)
            tim = tim_all[start:end + 1] if end < len(tim_all) else tim_all[start:]
            ele = ele_all[start:end + 1] if end < len(ele_all) else ele_all[start:]
            azi = azi_all[start:end + 1] if end < len(azi_all) else azi_all[start:]
            snr = snr_all[start:end + 1] if end < len(snr_all) else snr_all[start:]

            # MATLAB intersect(cf1,cf2,'stable') 等效实现
            cf1 = np.where((ele > ele_s) & (ele < ele_d))[0]
            cf2 = np.where((azi > azi_s) & (azi < azi_d))[0]
            _, cf1_idx, cf2_idx = np.intersect1d(cf1, cf2, return_indices=True)
            cf = cf1[np.sort(cf1_idx)]  # 保持原始顺序

            if cf.size >= data_num:
                w1, w2 = cf[0], cf[-1]
                vtsnr = 10 ** (snr / 20).astype(float)

                y1 = np.sin(ele[cf].astype(float) * np.pi / 180)
                y2 = np.sin(ele.astype(float) * np.pi / 180)

                # 信号分离
                if method == 1:  # 多项式拟合
                    x = np.arange(1, len(snr) + 1)  # 创建 1:length(snr) 的数组
                    coefficients = np.polynomial.polynomial.polyfit(x, vtsnr, 2)  # 二次拟合
                    # 计算拟合值
                    vtdsnr1 = np.polynomial.polynomial.polyval(len(snr), coefficients)
                    # 计算残差
                    vtdsnr2 = vtsnr - vtdsnr1
                    # 提取 w1 到 w2 之间的数据
                    vtdsnr3 = vtdsnr2[w1:w2+1]
                elif method == 2:  # EMD
                    # 执行 EMD 分解
                    decomposer = EMD(vtsnr)
                    imfs = decomposer.decompose()  # IMF 列表（每个元素是一个 IMF）

                    m = len(imfs)  # IMF 层数

                    # 改用列表存储层数（避免未初始化的 numf 问题）
                    if 'numf' not in locals():  # 如果 numf 未定义，初始化为空列表
                        numf = []
                    numf.append(m)  # 添加当前层数

                    # 重构信号（去除最后一个 IMF，即残差）
                    vtdsnr2 = np.sum(imfs[:-1], axis=0)  # 对所有 IMF（除残差外）求和

                    # 提取 w1:w2 之间的数据（注意 Python 是 0-based 索引）
                    vtdsnr3 = vtdsnr2[w1: w2+1]
                elif method == 3:  # 小波
                    n = p1
                    coeffs = pywt.wavedec(vtsnr, 'db4', level=n)

                    coeffs_a = [coeffs[0]] + [np.zeros_like(c) for c in coeffs[1:]]
                    pywt.waverec(coeffs_a, 'db4', mode='sym')

                    # 重构各层细节系数
                    d = []
                    for k in range(1, n + 1):
                        level_index = n + 1 - k  # coeffs[1]对应d8，coeffs[8]对应d1
                        coeffs_d = [np.zeros_like(coeffs[0])]
                        for i in range(1, n + 1):
                            if i == level_index:
                                coeffs_d.append(coeffs[i])
                            else:
                                coeffs_d.append(np.zeros_like(coeffs[i]))
                        d_k = pywt.waverec(coeffs_d, 'db4', mode='sym')
                        d.append(d_k)
                    vtdsnr2 = np.zeros(d[0].size)
                    for i in range(p2, p3):
                        vtdsnr2 += d[i - 1]
                    vtdsnr3 = vtdsnr2[w1:w2 + 1]

                    # Lomb-Scargle分析
                P, f, alpha = lomb(vtdsnr3, y1)
                h = f * L_r / 2
                wf = np.where((h > h_s) & (h < h_d))[0]
                if wf.size > 0:
                    f1 = f[wf]
                    h1 = h[wf]
                    P1 = P[wf]
                else:
                    f1 = np.array([])
                    h1 = np.array([])
                    P1 = np.array([])

                if len(P1) > 3:
                    peaks, loc = matlab_style_findpeaks(P1)
                    if peaks.size:
                        wh = np.where(P1 == max(peaks))[0]
                        P2 = np.delete(P1, wh)
                        zp = np.mean(P2)
                        zpb = P1[wh] / zp

                        if wh.size == 1 and max(peaks) > peak_s and zpb > zqb_s:
                            righth = h1[wh]
                            rightf1 = f1[wh]

                            ocean_h = Ant_h - righth

                            tim1 = tim[w1]
                            tim2 = tim[w2]

                            # 转换为字符串并解析为datetime对象
                            tim11 = datetime.strptime(str(tim1)[:14], "%Y%m%d%H%M%S")
                            tim22 = datetime.strptime(str(tim2)[:14], "%Y%m%d%H%M%S")

                            # 计算中间时间
                            time_diff = tim22 - tim11
                            timf = tim11 + time_diff / 2

                            # 格式化为字符串并转换为数值
                            timf1 = timf.strftime("%Y%m%d%H%M%S")
                            timf2 = np.double(timf1)

                            # 保存结果
                            results['bbb1'].append([
                                tim11,
                                int(u),
                                ocean_h
                            ])
                            results['frp1'].append(np.column_stack([f, P]))
                            results['frp2'].append(y1)
                            results['frp3'].append(vtsnr[cf].astype(float))
                            results['frp5'].append(y2)
                            results['frp6'].append(vtdsnr3)
                            results['mpeak'].append(max(peaks))
                            results['rightf'].append(rightf1)
                            i += 1

    # 转换为numpy数组
    # results['bbb1'] = np.array(results['bbb1'])
    results['mpeak'] = np.array(results['mpeak'])
    results['rightf'] = np.array(results['rightf'])

    return results


def interpolate_time_series(time, high):
    """
    对时间序列进行每分钟插值，确保时间连续

    参数:
        time (list[datetime.datetime]): 原始时间列表
        high (list[float]): 对应值的列表

    返回:
        complete_times (list[datetime.datetime]): 完整每分钟时间序列
        interpolated_high (list[float]): 插值后的结果值序列
    """
    if not time:
        return [], []

    # 按时间排序并保持对应关系
    sorted_pairs = sorted(zip(time, high), key=lambda x: x[0])
    time_sorted, high_sorted = zip(*sorted_pairs)
    time_sorted = list(time_sorted)
    high_sorted = list(high_sorted)

    # 生成完整时间序列（每分钟）
    min_time = time_sorted[0]
    max_time = time_sorted[-1]
    current_time = min_time
    complete_times = []
    while current_time <= max_time:
        complete_times.append(current_time)
        current_time += timedelta(minutes=1)

    # 线性插值处理
    interpolated_high = []
    for t in complete_times:
        index = bisect.bisect_left(time_sorted, t)
        if index < len(time_sorted) and time_sorted[index] == t:
            interpolated_high.append(high_sorted[index])
        else:
            # 处理边界情况
            if index == 0 or index >= len(time_sorted):
                interpolated_high.append(high_sorted[0] if index == 0 else high_sorted[-1])
            else:
                # 计算线性插值
                t_prev = time_sorted[index - 1]
                t_next = time_sorted[index]
                h_prev = high_sorted[index - 1]
                h_next = high_sorted[index]

                delta = (t - t_prev).total_seconds()
                total_delta = (t_next - t_prev).total_seconds()
                ratio = delta / total_delta if total_delta != 0 else 0
                interpolated_high.append(h_prev + (h_next - h_prev) * ratio)

    return complete_times, interpolated_high


if __name__ == "__main__":
    app = QApplication([])  # 创建应用实例
    path = get_file_name()
    data = read_excel_range(path, 'A3:B3096')
    time = [d[0] for d in data]
    # satellite_data = read_satellite_data(path)
    # sat_stats = satellite_data['SAT'].value_counts().sort_index()
    # labels = list(sat_stats.index)
    pass
